//Path: ISPD_Contest/sizer-v1.0

#include "optimization.h"
//#include "coneSampling.h"
#include "utility.h"
#include <algorithm>
#include "extendedverilogparser.h"
#include "timer_interface.h"
#include "time.h"
#include "thread.h"
#include <ctime>


#include <boost/random/uniform_int.hpp>
#include <boost/random/mersenne_twister.hpp>

#include "validate.cpp"
#include "parser_helper.h"
#include "extendedlibparser.h"
#include "extendedtimingparser.h"
#include "extendedspefparser.h"
#include "extendedsdcparser.h"
#include "extendedverilogparser.h"
#include "circuitgraph.hpp"

//global variables, Min
CircuitGraph* graphInPtr;
ExtendedVerilogParser* vpPtr;
ExtendedSdcParser* sdcPtr;
ExtendedLibParser* lpPtr;
ExtendedTimingParser* tpPtr;
//vector<string> optList;

using namespace std ;
typedef boost::mt19937 gen;


bool lessLeakage(const string &s1, const string &s2)
{
        LibParserCellInfo *LPCI1, *LPCI2;
        LPCI1 = &(lpPtr->mapStandardLibraryCells[s1]);
        LPCI2 = &(lpPtr->mapStandardLibraryCells[s2]);
        
        return (LPCI1->leakagePower < LPCI2->leakagePower);
}

void minLeakage (CircuitGraph& graphIn)
{
        int i,j;
        int numberOfCells;
        LibParserCellInfo *LPCI;
        
        double temp_leakage;
        string selected_cell_name;
        cout << "Choosing minimum leakage cells...." << endl;
        
        int vn = boost::num_vertices(graphIn) ;
        cout << "Number of gates: " << vn << endl ;
        
        for( i = 0; i < vn; i++)
        {                
                temp_leakage = 10000000.0;//larger enough?
                numberOfCells = graphIn[i].listOfCells.size() ;

                for(j = 0; j < numberOfCells; j++)
                {
                        LPCI = &(lpPtr->mapStandardLibraryCells[graphIn[i].listOfCells[j]]);
                        if(LPCI->leakagePower < temp_leakage)
                        {
                                temp_leakage = LPCI->leakagePower;
                                selected_cell_name = graphIn[i].listOfCells[j];
                        }
                }
                
                if(numberOfCells > 1)//get rid of the DFFs
                        graphIn[ i ].cellName = selected_cell_name;
                
                LPCI = &(lpPtr->mapStandardLibraryCells[ graphIn[ i ].cellName ]);
                
                //sort the cells of same footprint in less leakage order
                std::sort(graphIn[i].listOfCells.begin(),graphIn[i].listOfCells.end(),lessLeakage);                
        }
        
}

bool moreViolation(const int i1, const int i2)
{
        return ((*graphInPtr)[i1].Slew_Violation + (*graphInPtr)[i1].Slack_Violation + (*graphInPtr)[i1].Cap_Violation > 
                (*graphInPtr)[i2].Slew_Violation + (*graphInPtr)[i2].Slack_Violation + (*graphInPtr)[i2].Cap_Violation);
}

double violationCheck(CircuitGraph& graphIn, bool write_to_file, ofstream& out, ofstream& vio)
{
        int count_cap_vio = 0;
        int count_slew_vio = 0;
        int count_slack_vio = 0;
        LibParserCellInfo *LPCI;
        LibParserCellInfo *LPCI_;
        double T_Output_Cap;
        double Cap_Violation = 0.0;
        double Slack_Violation = 0.0;
        double Slew_Violation = 0.0;
        lpPtr->default_max_transition = 300.0;// same for all
        
        vector<LibParserPinInfo>::iterator it;
        boost::graph_traits<CircuitGraph>::vertex_iterator vi, vi_end ;
	boost::graph_traits<CircuitGraph>::out_edge_iterator oi, oi_end ;

	vio << "noVio" << "\t" << "capVio" << "\t" << "slackVio" << "\t" << "capslackVio" << "\t"
            << "slewVio" << "\t" << "capslewVio" << "\t" << "slewslackVio" << "\t" << "allVio" << endl;	
        for (boost::tie(vi, vi_end) = boost::vertices(graphIn) ; vi != vi_end ; ++vi)
	{
                
                vertex_descriptor in = (*vi) ;
                graphIn[ in ].Slew_Violation = 0.0;
                graphIn[ in ].Slack_Violation = 0.0;
                graphIn[ in ].Cap_Violation = 0.0;

                if(graphIn[ in ].gateType == 0 || graphIn[ in ].gateType == 1)  
                        continue;
                
                LPCI = &(lpPtr->mapStandardLibraryCells[ graphIn[ in ].cellName ]);
                
                //check the slew violation, for input pins of
                //Combinational and Sequential cells
                
                for(it = LPCI->pins.begin(); it != LPCI->pins.end(); it++)
                        if(it->name != "o")//not the output pins
                        {
                                double temp_violation = 0.0;
                                double temp_slack_violation = 0.0;
                                string tmp_name = graphIn[ in ].instanceName + "/" + it->name;
                                
                                if(tpPtr->PinsTiming[tmp_name].riseTransition > lpPtr->default_max_transition)
                                        temp_violation += tpPtr->PinsTiming[tmp_name].riseTransition - lpPtr->default_max_transition;
                                
                                if(tpPtr->PinsTiming[tmp_name].fallTransition > lpPtr->default_max_transition)
                                        temp_violation += tpPtr->PinsTiming[tmp_name].fallTransition - lpPtr->default_max_transition;
                                
                                if(tpPtr->PinsTiming[tmp_name].riseSlack < 0)
                                        temp_slack_violation += abs(tpPtr->PinsTiming[tmp_name].riseSlack);
                                
                                if(tpPtr->PinsTiming[tmp_name].fallSlack < 0)
                                        temp_slack_violation += abs(tpPtr->PinsTiming[tmp_name].fallSlack);
                                
                                graphIn[ in ].Slew_Violation += temp_violation;                                
                                graphIn[ in ].Slack_Violation += temp_slack_violation;                                
                                Slew_Violation += temp_violation;
                        }
                
                //check the slack violation, for sequential gates
                if(graphIn[ in ].gateType == 3)
                {
                        for(it = LPCI->pins.begin(); it != LPCI->pins.end(); it++)
                                if(it->name != "o" && it->name != "ck")//not the output pins
                                {
                                        double temp_violation = 0.0;
                                        string tmp_name = graphIn[ in ].instanceName + "/" + it->name;
                                        
                                        if(tpPtr->PinsTiming[tmp_name].riseSlack < 0)
                                                temp_violation += abs(tpPtr->PinsTiming[tmp_name].riseSlack);
                                        
                                        if(tpPtr->PinsTiming[tmp_name].fallSlack < 0)
                                                temp_violation += abs(tpPtr->PinsTiming[tmp_name].fallSlack);
                                        
                                        //for sequential circuit, should be
                                        //only one net connect to DFF input
                                        
                                        graphIn[ in ].Slack_Violation += temp_violation;
                                        Slack_Violation += temp_violation;
                                }
                }
                
                //check the output cap violation
                T_Output_Cap = 0.0;
                for ( boost::tie(oi, oi_end) = boost::out_edges(in, graphIn) ; oi != oi_end ; ++oi )
                {
                        //finding the pin connect to PI, for driver,
                        //instance name and pin name and cell name are same
                        
                        //check the slack and slew violation, for POs
                        if(graphIn[target((*oi), graphIn)].gateType == 1)//is PO
                        {
                                double temp_slack_violation = 0.0;
                                double temp_slew_violation = 0.0;
                                        
                                if(tpPtr->PortsTiming[graphIn[(*oi)].netName].riseSlack < 0)
                                        temp_slack_violation += abs(tpPtr->PortsTiming[graphIn[(*oi)].netName].riseSlack);
                                
                                if(tpPtr->PortsTiming[graphIn[(*oi)].netName].fallSlack < 0)
                                        temp_slack_violation += abs(tpPtr->PortsTiming[graphIn[(*oi)].netName].fallSlack);
                                
                                if(tpPtr->PinsTiming[graphIn[(*oi)].netName].riseTransition > lpPtr->default_max_transition)
                                        temp_slew_violation += tpPtr->PinsTiming[graphIn[(*oi)].netName].riseTransition - lpPtr->default_max_transition;
                                
                                if(tpPtr->PinsTiming[graphIn[(*oi)].netName].fallTransition > lpPtr->default_max_transition)
                                        temp_slew_violation += tpPtr->PinsTiming[graphIn[(*oi)].netName].fallTransition - lpPtr->default_max_transition;
                                
                                Slack_Violation += temp_slack_violation;
                                Slew_Violation += temp_slew_violation;

                                //for PO, the violation comes from its
                                //fan-in gates
                                graphIn[source((*oi), graphIn)].Slack_Violation += temp_slack_violation;                                
                                graphIn[source((*oi), graphIn)].Slew_Violation += temp_slew_violation;                                
                        }
                                                
                        //net name should be unique
                        T_Output_Cap += graphIn[(*oi)].netParasiticLoad;
                        
                        LPCI_ = &(lpPtr->mapStandardLibraryCells[graphIn[target((*oi), graphIn)].cellName]); 
                        //cout<<"Target Pin name is "<<graphIn[(*oi)].targetPinName<<endl;
                        
                        for( it = LPCI_->pins.begin(); it != LPCI_->pins.end(); it++ )
                                if(it->name == graphIn[(*oi)].targetPinName)
                                        break;
                        
                        if(it != LPCI_->pins.end())
                                T_Output_Cap += (*it).capacitance;
                        else//should go back to the spec file for the output load
                                T_Output_Cap += sdcPtr->outputs_load[graphIn[(*oi)].netName];
                }
                
                for( it = LPCI->pins.begin(); it != LPCI->pins.end(); it++ )
                        if(it->name == "o")
                                break;
                
                if(it == LPCI->pins.end())
                        cout<<"No Way"<<endl;
                
                //cout<<"node cell name is "<< graphIn[in].cellName << endl;
                //cout<<"node instance name is "<< graphIn[in].instanceName << endl;
                //cout<<"Max cap is "<< (*it).maxCapacitance << endl;
                if( (*it).maxCapacitance < T_Output_Cap){
                        Cap_Violation += T_Output_Cap - (*it).maxCapacitance;
                        graphIn[ in ].Cap_Violation += T_Output_Cap - (*it).maxCapacitance;
                }
        }
        
        int stat[8];
        memset(stat, 0, 8 * sizeof(int));
        int flag1, flag2, flag3;
        
        int vn = boost::num_vertices(graphIn) ;
        for(int i = 0; i < vn; i++)
        {
                flag1 = 0;
                flag2 = 0;
                flag3 = 0;
                
                if(graphIn[ i ].Cap_Violation > 0.0)
                {
                        flag1 = 1;
                        count_cap_vio++;
                }
                if(graphIn[ i ].Slack_Violation > 0.0)
                {
                        flag2 = 1;
                        count_slack_vio++;
                }
                if(graphIn[ i ].Slew_Violation > 0.0)
                {
                        flag3 = 1;
                        count_slew_vio++;
                }
                
                stat[flag1 + flag2 * 2 + flag3 * 4]++;
        }
        
        for(int i = 0; i < 8; i++)
        {
                switch(i){
	                case 0: //vio<<"Number of gates with no violations "<<stat[0]<<endl;
				vio<<stat[0]<<"\t";
                                break;
                        case 1: //vio<<"Number of gates with only cap violation "<<stat[1]<<endl;
				vio<<stat[1]<<"\t";
                                break;
                        case 2: //vio<<"Number of gates with only slack violation "<<stat[2]<<endl;
				vio<<stat[2]<<"\t";
                                break;
                        case 3: //vio<<"Number of gates with both cap and slack violations "<<stat[3]<<endl;
				vio<<stat[3]<<"\t";
                                break;
                        case 4: //vio<<"Number of gates with only slew violation "<<stat[4]<<endl;
				vio<<stat[4]<<"\t";
                                break;
                        case 5: //vio<<"Number of gates with both cap and slew violations "<<stat[5]<<endl;
				vio<<stat[5]<<"\t";
                                break;
                        case 6: //vio<<"Number of gates with both slack and slew violations "<<stat[6]<<endl;
				vio<<stat[6]<<"\t";
                                break;
                        case 7: //vio<<"Number of gates with all types of  violations "<<stat[7]<<endl;
				vio<<stat[7]<<endl;
                                break;
                        default:
                                break;
                }
        }
        
        //for testing
        /*
          for(int i = 0; i < vn; i++)
          {
          cout<<"Cell Name: "<< graphIn[ i ].cellName <<endl;
          cout<< "Slack Violation is  "<< graphIn[ i ].Slack_Violation << "\t"
          << "Slew Violation is  "<< graphIn[ i ].Slew_Violation << "\t"
          << "Cap Violation is  "<< graphIn[ i ].Cap_Violation << endl;
          }
        */
        
        double Total_Violation = Slew_Violation + Slack_Violation + Cap_Violation;
        if(write_to_file)
        {
                out << Slack_Violation << "\t" << Slew_Violation 
                    << "\t" << Cap_Violation << "\t" << Total_Violation 
                    << "\t" << graphIn.accumTotalLeakage(lpPtr->mapStandardLibraryCells) 
                    << "\t" << count_slack_vio << "\t" << count_slew_vio << "\t" << count_cap_vio;
        }
        else
        {
                cout<<"From my Evaluation script....."<<endl;
                cout<< "Slack Violation is " << Slack_Violation << endl;
                cout<< "Slew Violation is " << Slew_Violation <<endl;
                cout<< "Cap Violation is " << Cap_Violation << endl;
                cout<< "Total Violation is " << Total_Violation << endl;
                cout << "The leakage power is : " << graphIn.accumTotalLeakage(lpPtr->mapStandardLibraryCells) << endl ;
        }
        
        int mode;
        if(Slack_Violation > Slew_Violation && Slack_Violation > Cap_Violation)
                graphIn.mode = 3;
        else if(Slew_Violation > Slack_Violation && Slew_Violation > Cap_Violation)
                graphIn.mode = 2;
        else if(Cap_Violation > Slack_Violation && Cap_Violation > Slew_Violation)
                graphIn.mode = 1;
        else
                graphIn.mode = 0;
        
        out.close();
        
        //return Slack_Violation;
        return Total_Violation;
}


int main (int argc, char* argv[]) 
{
        if (argc != 3) {
		cout << "Usage: " << argv[0] << " benchmark_name library_file" << endl ;
		exit(0) ;
	}

	string contest_dir, benchmark_dir ;
	
	contest_dir = argv[1]; 
	benchmark_dir = argv[2];
	
        cout<<"Benchmark directory is "<<benchmark_dir<<endl;
        
	clock_t startReadStandardLibraryCell = clock() ;
	// 1. Read Standard Library Cell
	//------------------------------------------------------------------------------------
	string standardLibFile = contest_dir+"/lib/contest.lib" ;
	cout << "Start reading standard library cell ( " <<  standardLibFile << " )" << endl ;
	ExtendedLibParser lp (standardLibFile) ;
	lp.readStandardLibraryCell () ;
        lpPtr = &lp;
        //cout<<"Default Max Transition is " << lpPtr->default_max_transition <<endl;


        // 2. Read Sdc File
        string sdcFile = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + ".sdc" ;
        ExtendedSdcParser sdcp(sdcFile);
        sdcp.readSdcFile();
        sdcPtr = &sdcp;
	//------------------------------------------------------------------------------------
	clock_t endReadStandardLibraryCell = clock() ;
	
	
	clock_t startReadSpef = clock() ;
	// 3. Read Parasitic Load
	//-----------------------------------------------------------------------------------
	string spefFile = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + ".spef" ;
	cout << "Start reading parasitic load from " << spefFile << endl ;
	ExtendedSpefParser sp (spefFile) ;
	sp.readSpefFile () ;
	//-----------------------------------------------------------------------------------
	clock_t endReadSpef = clock() ;

	
	// 4. Initialize the circuit graph
	//-----------------------------------------------------------------------------------
	cout << "The graph is initialized..." << endl;
	CircuitGraph inputCircuit ;
        graphInPtr = &inputCircuit;
	//-----------------------------------------------------------------------------------

	
	clock_t startReadVerilog = clock() ;
	// 5. Read Verilog File
	//-----------------------------------------------------------------------------------
	string verilogFile = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + ".v" ;
	cout << "Start reading verilog file " << verilogFile << endl ;
	ExtendedVerilogParser vp (verilogFile) ;
        vpPtr = &vp;
	vp.readVerilogFile(inputCircuit, lp.mapStandardLibraryCells) ;
	cout << "End reading verilog file..." << endl ;
	//-----------------------------------------------------------------------------------
	clock_t endReadVerilog = clock() ;
        

	// 6. Udate edges in graph
	//-----------------------------------------------------------------------------------
	inputCircuit.updateConnectivity(vp.verilogConnectivity, sp.mapNetParasiticLoads) ;
	//-----------------------------------------------------------------------------------
	
	//inputCircuit.printGateProperty < string, gateProperty> (&gateProperty::cellName) ;
	
	cout << "The graph is ready for optimization..." << endl ;
        cout.precision(3) ;
	double leakageBefore = inputCircuit.accumTotalLeakage(lp.mapStandardLibraryCells) ;
	//double leakageBefore = 0.0;
	clock_t startOptimization = clock() ;
        
        /*Amir's part......................*/
        //6. Read .sdc file                                                                                                      
        // -----------------------------------------------------------------------------------
        //string sdcFile = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + ".sdc" ;
        /*cout << "Start reading sdc file " << sdcFile << endl ;
          ExtendedSdcParser sdp (sdcFile) ; 
          string clockName ;
          string clockPort ;
          double period ;
        
          sdp.read_clock (clockName, clockPort, period) ;
          sdp.readInputDelays () ;
          sdp.readInputDrivers () ;
          sdp.readOutputDelays () ;
          sdp.readOutputLoads () ;*/
        sdcp.updateOutputCap(inputCircuit) ;
        sdcp.updateInputTime (inputCircuit, lp) ;

        //----------------------------------------------------------------------------------
        //cout << "The graph is ready for optimization..." << endl ;
        // Find the range of Output Capacitance for each gate and store
        // that in a file                                            
        //----------------------------------------------------------------------------------------------                          
        string capFile = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + "_capRange.txt" ;
        ofstream outCapacitance(capFile.c_str()) ;
        StoreOutCapacitance storeFunc ; 
        inputCircuit.updateMinMaxOutputCap (lp, storeFunc, outCapacitance, true) ;
        //----------------------------------------------------------------------------------------------                          

        // fill each node in the circuit with library cells that have no
        // output violations                                        
        inputCircuit.fillNoCapViolationCells (lp) ;
        /*Amir's part......................*/
        
	// 7. Initialize optimization, 
        // (1) size all cells to maximum power saving
	
	Optimization op (contest_dir, benchmark_dir, 3, &minLeakage) ;
	
	cout << "Call updater function..." << endl ;
	//op.updateCellType (inputCircuit) ;
        
	// set sizes to maximum delay
	inputCircuit.updateSortedNoCapViolation(lp) ;
	inputCircuit.updateSizes() ;

	cout << "Make the sizer file... " << endl ;
	op.buildSizerFile (inputCircuit, false) ;
        
        //(2) delete the timing file first, otherwise will have interface error 
        string timingFile = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + ".timing" ;
	//ifstream infile(timingFile.c_str());
        //if(infile)
        //remove( timingFile.c_str() );
        
        cout << "Call timer..." << endl ;
        op.callTimer() ;
        cout << "Finished!!!" << endl ;
        clock_t endOptimization = clock() ;
        
        //(3) parsing the timing file for the first time 
        ExtendedTimingParser tp (timingFile) ;
        tp.readTimingFile();
        tpPtr = &tp;
        //tp.closeTimingFile();

	//------------------------------------------------------------------------------------Amir---------------------------------------------------------------------	
         std::string violationStr = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + "_violations.txt";
	// std::string changeCellStr = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + "_cellsChange.txt";
	// std::string capViolationStr = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + "_myCap.txt";

	// int round = 0 ;
    	// int numberOfCellChanged ;
	// inputCircuit.fillCellSizes() ;
	
	// ofstream cellChangeFile(changeCellStr.c_str()) ;
	 ofstream violationFile(violationStr.c_str()) ;
	
	
	 violationFile << "TNS\t" << "TNS Decrease%\t"
                       << "TotalSlew\t" << "TotalCap\t" << "TotalViolations\t" 
                       << "Leakage\t" << "Leakage Increas%\t"
                       << "Best TNS\t" << "Best Leakage\t"
                       << "Best Cap Viol\t" << "Best Slew Viol\t"
                       << "Changed Cells\t" << "Changed Cells %\t"
                       << "RunTime\t" << endl  ;


        // double percentage = 1;
        // inputCircuit.updateLevelDistance() ;

        // round = 0 ;
        // //op.updateCellType (inputCircuit) ;
	
        // // set to minimum leakage
        // inputCircuit.updateSizes() ;
		
        // //violationFile << "The percentage: " << percentage << endl << endl ;
		
        // int bestIteration = 0;
        // double bestTNS = std::numeric_limits<double>::max() ;
        // double bestLeakage = std::numeric_limits<double>::max() ;
        // double bestSlew = std::numeric_limits<double>::max() ;
        // double bestCap = std::numeric_limits<double>::max() ;
		
        // inputCircuit.fillBestSolution() ;
		
         double firstTNS = 0.0 ;
         double firstLeakage = 0.0 ;
		
        // std::vector<std::string> samples ;
        // bool equal ;
        // inputCircuit.sampleGateAngleGreedy (105, lp, 4, samples
        //                                     , 0, 1, equal) ;
		
		
        // for (int i = 0 ; i < 1000 ; ++ i)
        // {
        //         cout << "******** Round " << i << " ***********" << endl ;
        //         // clock first round
        //         clock_t startRound1 = clock() ;
			
			
        //         // violation object
        //         violation_ctrl MyVc(contest_dir, benchmark_dir, standardLibFile);
			
        //         // Starting point for optimization
        //         cout << "********* Optimization Round *********" << round << endl;
			
        //         inputCircuit.updateNodeSlackVector(lp, tp, true) ;
        //         double totalCells = inputCircuit.upsizeCells(1.0, numberOfCellChanged,cellChangeFile) ;
			
			
        //         bool noSlew = false ;
        //         bool noSlack = false ;
        //         bool noCap = false ;
        //         cout << "Make the sizer file... " << endl ;
        //         op.buildSizerFile (inputCircuit, false) ;
			
        //         double slackViolation = 0.0 ;
        //         double slewViolation = 0.0 ;
        //         double capViolation = 0.0 ;
        //         double leakage = 0.0 ;
			
        //         MyVc.check_violations(firstTNS, firstLeakage, violationFile, noSlew, noSlack, noCap,
        //                               slewViolation, slackViolation, capViolation, leakage) ;
										
        //         if (i == 0)
        //         {
        //                 firstLeakage = leakage ;
        //                 firstTNS = -slackViolation ;
        //         }
										
        //         if ( ( (bestTNS  + slackViolation) / bestTNS ) < 0.01  && ( (bestTNS  + slackViolation) / bestTNS ) > 0.0 )
        //                 if (leakage < bestLeakage)
        //                 {
        //                         cout << "Leakage improved............" << endl ;
						
        //                         inputCircuit.fillBestSolution() ;
        //                         bestTNS = -slackViolation ;
        //                         bestIteration = i ;
        //                         bestLeakage = leakage ;
        //                         bestSlew = slewViolation ;
        //                         bestCap = capViolation ;
        //                 }
			
        //         if ( ( (bestTNS  + slackViolation) / bestTNS ) > 0.01 )
        //         {
        //                 cout << "TNS improved............" << endl ;
				
        //                 inputCircuit.fillBestSolution() ;
        //                 bestTNS = -slackViolation ;
        //                 bestIteration = i ;
        //                 bestLeakage = leakage ;	
        //                 bestSlew = slewViolation ;
        //                 bestCap = capViolation ;				
        //         }
			
			
        //         violationFile << bestTNS << "\t" ; 
        //         violationFile << bestLeakage << "\t" ;
        //         violationFile << bestCap << "\t" ;
        //         violationFile << bestSlew << "\t" ;
			
        //         violationFile << numberOfCellChanged << "\t" ;
        //         violationFile << ( totalCells - numberOfCellChanged ) / totalCells << "\t" ;
			
        //         cout << "Call timer..." << endl ;
        //         op.callTimer() ;
        //         cout << "Finished!!!" << endl ;
        //         tp.updateTimingFile(timingFile);
        //         inputCircuit.clearIsFixedFlag() ;
        //         clock_t endRound1 = clock() ;
        //         violationFile << (double)(endRound1 - startRound1) / (double)CLOCKS_PER_SEC << endl ;
        //         cout << "*************************************" << endl ;
        //         if (i - bestIteration > 10)
        //                 break ;
        // }
		
        // violationFile << endl << endl ;
        // violationFile << "Best Solution(TNS): " << bestTNS << endl ; 
		
        // cout << "Start Phase 2...." << endl ;
        // cout << "#############################################################################"<<endl ;
        // violationFile << endl << endl << endl ;
		
        // bestIteration = 0 ;
		
        // for (int i = 0 ; i < 1000 ; ++ i)
        // {
        //         cout << "******** Round " << i << " ***********" << endl ;
        //         // clock first round
        //         clock_t startRound2 = clock() ;
			
			
        //         // violation object
        //         violation_ctrl MyVc(contest_dir, benchmark_dir, standardLibFile);
			
        //         // Starting point for optimization
        //         cout << "********* Optimization Round *********" << round << endl;
			
        //         inputCircuit.updateNodeSlackVector(lp, tp, false) ;
        //         double totalCells = inputCircuit.upsizeCells(1.0, numberOfCellChanged,cellChangeFile) ;
			
        //         //violationFile << round << "\t";
        //         //cout<< (double)(endRound - startRound) / (double)CLOCKS_PER_SEC<<endl;
			
        //         bool noSlew = false ;
        //         bool noSlack = false ;
        //         bool noCap = false ;
        //         cout << "Make the sizer file... " << endl ;
        //         op.buildSizerFile (inputCircuit, false) ;
			
        //         double slackViolation = 0.0 ;
        //         double slewViolation = 0.0 ;
        //         double capViolation = 0.0 ;
        //         double leakage = 0.0 ;
			
        //         MyVc.check_violations(firstTNS, firstLeakage, violationFile, noSlew, noSlack, noCap,
        //                               slewViolation, slackViolation, capViolation, leakage) ;
										
        //         if ( ( (bestTNS  + slackViolation) / bestTNS ) < 0.01 && ( (bestTNS  + slackViolation) / bestTNS ) > 0.0)
        //                 if (leakage < bestLeakage)
        //                 {
        //                         cout << "Leakage improved............" << endl ;
						
        //                         inputCircuit.fillBestSolution() ;
        //                         bestTNS = -slackViolation ;
        //                         bestIteration = i ;
        //                         bestLeakage = leakage ;
        //                         bestSlew = slewViolation ;
        //                         bestCap = capViolation ;
        //                 }
			
        //         if ( ( (bestTNS  + slackViolation) / bestTNS ) > 0.01 )
        //         {
        //                 cout << "TNS improved............" << endl ;
        //                 inputCircuit.fillBestSolution() ;
        //                 bestTNS = -slackViolation ;
        //                 bestIteration = i ;	
        //                 bestLeakage = leakage ;
        //                 bestSlew = slewViolation ;
        //                 bestCap = capViolation ;
        //         }
			
        //         violationFile << bestTNS << "\t" ; 
        //         violationFile << bestLeakage << "\t" ;
        //         violationFile << bestCap << "\t" ;
        //         violationFile << bestSlew << "\t" ;
			
			
        //         violationFile << numberOfCellChanged << "\t" ;
        //         violationFile << ( totalCells - numberOfCellChanged ) / totalCells << "\t" ;
			
        //         cout << "Call timer..." << endl ;
        //         op.callTimer() ;
        //         cout << "Finished!!!" << endl ;
        //         tp.updateTimingFile(timingFile);
        //         inputCircuit.clearIsFixedFlag() ;
        //         clock_t endRound2 = clock() ;
        //         violationFile << (double)(endRound2 - startRound2) / (double)CLOCKS_PER_SEC << endl ;
        //         cout << "*************************************" << endl ;
        //         if (i - bestIteration > 10)
        //                 break ;
        // }
		
        // violationFile << endl << endl ;
        // violationFile << "Best Solution(TNS): " << bestTNS << endl ; 
		
        // inputCircuit.downloadBestSolution() ;
        // op.buildSizerFile (inputCircuit, true) ;
	//------------------------------------------------------------------------------------Amir---------------------------------------------------------------------
	
        
        //------------------------------------------------------------------------------------Min---------------------------------------------------------------------
        //8. divided into cones and optimize each        
        Cone myCone;
        myCone.number_dffs(inputCircuit);
        myCone.TpPtr = &tp;
        myCone.LpPtr = &lp;
        myCone.clear_flag(inputCircuit);
        //myCone.topo_order_whole_graph(inputCircuit); 
        myCone.topo_order_dffs(inputCircuit); 
        myCone.clear_flag(inputCircuit);
        myCone.form_cones(inputCircuit);
        myCone.reset_cones();
        myCone.clear_flag(inputCircuit);
        
        string temp_dir = contest_dir + "/" + benchmark_dir;
        cout<<temp_dir<<endl;
        
        //may needs many rounds to reach a zero-violation solution        
        int count = 0;

        bool write_to_file = true;
        string resultFile = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + ".result2";
        ofstream out(resultFile.c_str());
        cout << " File name is "<< resultFile.c_str() <<endl;

        out<<"Benchmark"<<"\t\t\t\t\t"<<benchmark_dir<<endl;
        out<<"Round"<<"\t"<<"Slack_Vio"<<"\t"<<"Slew_Vio"<<"\t"
           <<"Cap_Vio"<<"\t"<<"Total_Vio"<<"\t"<<"Leakage"<<"\t"
           <<"#gateSalckVio"<<"\t"<<"#gateSlewVio"<<"\t"
           <<"#gateCapVio"<<"\t"<<"Cur Best"<<"\t"<<"Runtime"<<endl;
        
        //string violationFile = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + ".vio" ;
        ofstream vio("hoho");

        int phase = 0;bool state;
        int coarse = 0; double pre_itr_vio = 0.0;
        double temp_total_vio,cur_best_total_vio = 1.0e20;
        
        int vn = boost::num_vertices(inputCircuit) ;
        int cnt_fixed = 0;
        for(int i = 0; i < vn; i++)
        {
                string tmp = inputCircuit[i].cellName.substr(inputCircuit[i].cellName.size() - 3);
                if(tmp != "s01")
                {
                        inputCircuit[i].visited = 1;
                        cnt_fixed++;
                }
        }
        
        inputCircuit.nodes_under_inspection.clear();
        cout<<"fixed percentage is "<< (double)cnt_fixed / (double)vn <<endl; 
        
        cout << "********* Path-Based Sampling Starts......... *********"  << endl;
        while(1){
                // violation object
                violation_ctrl MyVc(contest_dir, benchmark_dir, standardLibFile);
			
                // Starting point for optimization
                cout << "********* Optimization Round " << count << "**********" << endl;
			
                //inputCircuit.updateNodeSlackVector(lp, tp, false) ;
                			
                bool noSlew = false ;
                bool noSlack = false ;
                bool noCap = false ;
                
                cout << "Make the sizer file... " << endl ;
                op.buildSizerFile (inputCircuit, false) ;
			
                double slackViolation = 0.0 ;
                double slewViolation = 0.0 ;
                double capViolation = 0.0 ;
                double leakage = 0.0 ;
		
                MyVc.check_violations(firstTNS, firstLeakage, violationFile, noSlew, noSlack, noCap,
                                      slewViolation, slackViolation, capViolation, leakage) ;
		
                /*
                  int vn = boost::num_vertices(inputCircuit) ;
                  for(int i = 0; i < vn; i++)
                  {
                  cout<<"gate "<< i << " " << inputCircuit[i].instanceName <<" has violations :"<<endl;
                  cout<<inputCircuit[i].Slack_Violation<<"\t";
                  cout<<inputCircuit[i].Slew_Violation<<"\t";
                  cout<<inputCircuit[i].Cap_Violation<<endl;
                  }
                */
                out<<count<<"\t";
                temp_total_vio = violationCheck(inputCircuit, write_to_file, out, vio);
                inputCircuit.showNodesUnderInspection();
                
                myCone.update_DFF_timing(inputCircuit);
                myCone.normal_cone_sorting();
                //myCone.form_hybrid_cones(inputCircuit);
                //myCone.hybrid_cone_sorting();

                out.open(resultFile.c_str(), ios::app);
                if(cur_best_total_vio > temp_total_vio)
                        cur_best_total_vio = temp_total_vio;
                out<< "\t" << cur_best_total_vio << "\t";
                inputCircuit.nodes_under_inspection.clear();
                //vio<<"New Round"<<endl;
                //jump-out condition
                
                if(phase == 0)
                {
                        cout<<"Pre "<<pre_itr_vio<<endl;
                        if(pre_itr_vio >= temp_total_vio && ((pre_itr_vio - temp_total_vio)/pre_itr_vio < 0.02) )
                        {
                                out<<endl;
                                out<< "Phase 1 ends...."<<endl;
                                cout<< "Phase 1 ends...."<<endl;
                                //cin.get();
                                //out.close();
                                vio.close();
                                //phase = 1;
                                //continue;
                                //break;
                        }
                        else
                                pre_itr_vio = temp_total_vio;

                        cout<<"Cur "<<temp_total_vio<<endl;
                        cout << "Optimization Round " << count << endl;
                        clock_t startSampling = clock();
                        //state = myCone.sampling(inputCircuit, coarse);
                        myCone.heuristic3(inputCircuit);
                        ///myCone.heuristc_sizing(inputCircuit);
                        clock_t endSampling = clock();
                        out<<(double)(endSampling - startSampling) / (double)CLOCKS_PER_SEC<<endl;
                }
                else
                {
                        clock_t startFinerTuning = clock();
                        myCone.finer_tuning(inputCircuit);
                        clock_t endFinerTuning = clock();
                        out<<(double)(endFinerTuning - startFinerTuning) / (double)CLOCKS_PER_SEC<<endl;
                }
                
                cout << "Call updater function..." << endl ;
                //op.updateCellType (inputCircuit) ;
                cout << "Make the sizer file... " << endl ;
                op.buildSizerFile (inputCircuit, false) ;
                cout << "Call timer..." << endl ;
                op.callTimer() ;
                cout << "Finished!!!" << endl ;
                tp.updateTimingFile(timingFile);
                
                cin.get();
                if(state == true)
                {
                        //out<< "Phase 1 ends...."<<endl;
                        //if(coarse <= 3)
                        //coarse++;
                }
                //break;
                
                //if(temp_total_vio < 0.01)
                //break;
                
                count++;
        }
        
        out.close();
        vio.close();
        //finished and reporting
	cout << "Gate after optimization: " << endl;
	//inputCircuit.printGateProperty < string, gateProperty> (&gateProperty::cellName) ;
	
	cout.precision(3) ;
	cout << "The leakage power is (before optimization): " << leakageBefore << endl ;
	cout << "The leakage power is (after optimization): " << inputCircuit.accumTotalLeakage(lp.mapStandardLibraryCells) << endl ;
	
	//printEdgesProperty <string, netProperty> (sample, &netProperty::netName) ;
        
	cout.precision(5) ;
	double timeStandard = (double)(endReadStandardLibraryCell - startReadStandardLibraryCell) / (double)CLOCKS_PER_SEC ;
	double timeSpef = (double)(endReadSpef - startReadSpef) / (double)CLOCKS_PER_SEC ;
	double timeVerilog = (double)(endReadVerilog - startReadVerilog) / (double)CLOCKS_PER_SEC ; 
	double timeOptimization = (double)(endOptimization - startOptimization) / (double)CLOCKS_PER_SEC ;
	
	cout << "--------------Run time---------------" << endl ;
	cout << "Reading Standard Library Cell: " <<  timeStandard << endl;
	cout << "Reading SPEF: " <<  timeSpef << endl;
	cout << "Reading Verilog: " << timeVerilog << endl;
	cout << "Optimization: " << timeOptimization << endl;
	cout << "Total: " << timeStandard + timeSpef + timeVerilog + timeOptimization << endl ;
	cout << "-------------------------------------" << endl ;
        
        return 0;
}
